package pl.jdeveloper.derivato.logic;

import java.util.ArrayList;
import java.util.List;

import pl.jdeveloper.derivato.domain.Point;

public class NewtonPolynominal{
	private List<Point> points;
	double[] t;
	double[][] dividedDifferences;
	
	public NewtonPolynominal(){
		this(null);
	}
	
	public NewtonPolynominal(List<Point> points) {
		if (points!=null){
			this.points = points;
		} else {
			this.points = new ArrayList<Point>();
		}
		t=new double[points.size()];
		dividedDifferences=new double[points.size()][points.size()];
		wspolczynniki();		
	}

	double setIlorazy(int i,int j){
		if (j==0){
			return dividedDifferences[i][j];
		}
		else{
			dividedDifferences[i][j]=(setIlorazy(i,j-1)-setIlorazy(i-1,j-1))/(points.get(i).getX()-points.get(i-j).getX());
			return dividedDifferences[i][j];
		}
			
	}
	
	private void wspolczynniki(){
		for (int i=0; i<points.size(); i++){
			dividedDifferences[i][0]=points.get(i).getY();
		}
		dividedDifferences[points.size()-1][points.size()-1]=setIlorazy(points.size()-1,points.size()-1);
		for (int i=0; i<points.size(); i++){
			t[i]=dividedDifferences[i][i];
		}
	}
	
	
	public String getFormula(){
		String f="";
		boolean byl=false;
		for (int i=0; i<t.length; i++){
			if (t[i]!=0){
				if (t[i]>0  && byl) f+="+";
				f+=Rounder.round(t[i], 3) ;
				for (int j=0; j<i; j++){
					f+="*(x";
					if (points.get(j).getX()!=0){
						if (points.get(j).getX()<0){
							f+="+"+(-1)*points.get(j).getX();
						} 
						else{
							f+="-"+points.get(j).getX();
						}
					}
					f+=")";
				}
				byl=true;
			}
			
		}
		return f;
	}
	
	public void getClassicalFormula(List<Point> p, double t[],double tab[], int n){
		//double tt[]=new double[n];
		//tt[0]=t[n];
		double tt[]=new double[1];
		if (n==0) tab[0]=t[0];
		else{
			tt=new double[n];
			tt[0]=t[n];
		}
		for (int i=0; i<n; i++){
			
			
			double temp[]=new double[n+1];
			temp[0]=0;
			for (int j=0; j<=i; j++){
				temp[j+1]=tt[j];
				tt[j]*=(-1)*p.get(i).getX();
				//tt[j]+=temp[j];
			}
			for (int j=0; j<=i; j++){
				tt[j]+=temp[j];
				//System.out.println("aaa"+temp[j]);
			}
			//tt[i]+=temp[i];
			
		}
		for (int i=0; i<n; i++){
			tab[i]+=tt[i];
			
		}
		if (n==p.size()-1) return;
		getClassicalFormula(p, t, tab, n+1);
	}
	
	public void wspol(ArrayList<Point> p, double t[],double tab[], int n){
		if (n==p.size()) return;
		double tt[]=new double[n+1];
		tt[0]=t[n];
		for (int i=0; i<n; i++){
			double temp[]=new double[n+1];
			temp[0]=0;
			for (int j=0; j<=i; j++){
				temp[j+1]=tt[j];
				tt[j]=tt[j]*(-1)*p.get(i).getX();
			}
			//tt[i]*=(-1)*p.get(i).getX();
			for (int j=0; j<=i+1; j++){
				tt[j]+=temp[j];
			}
		}
		for (int i=0; i<=n; i++){
			tab[i]+=tt[i];
		}
		//if (n==p.size()-1) return; 
		wspol(p,t,tab,n+1);
	}
	
	
	
	
	public String getFoo(ArrayList<Point> p, double t[]){
//		String formula="";
		StringBuilder formula = new StringBuilder();
		boolean byl=false;
		double tab[]=new double[p.size()];
		for (int i=0; i<p.size(); i++){
			tab[i]=0;
		}
		wspol(p, t, tab, 0);
		for (int i=0; i<p.size(); i++){
			System.out.println(tab[i]);
			if (tab[i]!=0){
				if (tab[i]>0 && byl){
					formula.append("+");
				}
				formula.append(tab[i]);
				if (i>0){
					formula.append("*x^");
					formula.append(i);
				}
				byl=true;
			}
		}
		
		return formula.toString();
		
		
	}
	
	public String getHTMLClasic(ArrayList<Point> ob, double t[]) {
		StringBuilder formula = new StringBuilder();
		boolean first=false;
		double tab[]=new double[ob.size()];
		for (int i=0; i<ob.size(); i++){
			tab[i]=0;
		}
		wspol(ob, t, tab, 0);
		for (int i=0; i<ob.size(); i++){
			if (tab[i]!=0){
				if (tab[i]>0 && !first){
					formula.append("+");
				}
				if (tab[i]==-1 && i>0){
					formula.append("-");
				}
				if (Math.abs(tab[i])!=1 || i==0){
					formula.append(Rounder.round(tab[i], 3));
					if (i>0){
						formula.append("*");
					}
				}
				if (i>0){
					formula.append("<var>x");
					if (i>1) {
						formula.append("<sup>").append(i).append("</sup>");
					}
					formula.append("</var>");
				}
				first=false;
			}
		}
		
		return formula.toString();
	}
	
	public double horner(double x, int n){
		
		double wynik=0;
		if (n==points.size()-1) return t[n];
		wynik=t[n]+(x-points.get(n).getX())*horner(x,n+1);
		return wynik;
	}

}
